iT邦幫忙

2025 iThome 鐵人賽

DAY 10
1
自我挑戰組

用 C++ 實作簡易第一人稱視角遊戲:從入門到理解 Ray Casting系列 第 10

Day 10 | Ray Casting 前置階段回顧 ─ 從地圖到玩家視野的基礎鋪墊

  • 分享至 

  • xImage
  •  

大家好~ 這裡是鐵匠史密斯,
今天是鐵人賽的第十天,我們先稍微喘口氣,來回顧一下 Day 1 ~ Day 9 的進度與收穫。
也讓第一次看到這系列的朋友,能快速了解我們目前的知識鋪墊,接下來才能更順暢地進入 Ray Casting 演算法的核心。

進度回顧

Day 1-4:基礎工具與遊戲地圖

  1. Day 1:為什麼選擇用 C++ 製作第一人稱視角遊戲?
  2. Day 2-3:用 wchar_t* 在 Console 畫畫 ─ 認識畫面緩衝區 (Part 1 & Part 2)
  3. Day 4:用 wstring 寫出迷宮地圖 map

Day 5-9:玩家視野的構成要素

  1. Day 5:fPlayerXfPlayerY 玩家位置 與 地圖陣列的對應關係
  2. Day 6:screen 玩家視野畫面
  3. Day 7:fPlayerA 玩家朝向 & AoV 視野範圍
  4. Day 8:玩家旋轉方向的正負定義 & 單位向量概念
  5. Day 9:screenAoV 的關係 ─ 從玩家視野射出多條光線取得畫面資訊

小小心得

連續 9 天的發文,其實就是在「蓋地基」。
很多時候,我會急著看到 3D 畫面與演算法(一開始實作時看 C++ 大神 javidx9 的影片就是這樣XD),但沒有這些基本元素,Ray Casting 就像空中樓閣,無法落地。
甚至,後面的一些原理我也還沒完全釐清,但我還是會嘗試以我的角度去比喻、解釋這些原理。
畢竟,學習都是從模仿開始,再透過自己的理解轉化成自己的語言,並嘗試解說,這樣才能真正內化知識,不是嘛?

這幾天我最大的收穫,就是把腦中的空間想像,用圖解和程式碼結合起來。
這不只是寫遊戲,也是在練習「如何讓複雜的東西被看懂」。

明日 Day 11開始,我們就會正式進入Ray Casting核心的演算法,
包含:

  • 光線如何行進?
  • 如何判斷光線碰撞道牆面?
  • 如何根據距離決定牆在玩家視野 screen的高度、亮度(渲染)等等

先附上目前各個的初始化變數,記得
我們先把 screen 的變數重新初始化,
screen 的寬為 120
screen 的高為 40
也就是:

const int nScreenWidth{ 120 };
const int nScreenHeight{ 40 };

玩家目前初始化數值如下(包含 前幾日提到的 AOV 以及 fPlayerA 的初始化數值)

float fPlayerX{ 8.0f };
float fPlayerY{ 3.0f };
float fPlayerA{ 0.0f };

float fAOV{ 3.14159 / 4.0 };

附上目前的code:

#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;

int nMapWidth{ 16 };
int nMapHeight{ 16 };

float fPlayerX{ 8.0f };
float fPlayerY{ 3.0f };
float fPlayerA{ 0.0f };


float fAOV{ 3.14159 / 4.0 };

int main()
{
    const int nScreenWidth{ 120 };
    const int nScreenHeight{ 40 };

    // Create the canvas
    wchar_t* screen{ new wchar_t[nScreenWidth * nScreenHeight] };
    // Create elements in screen
    for (int i = 0; i < nScreenWidth * nScreenHeight; i++)
    {
        if (i < 1200)
            screen[i] = L' ';
        else
            screen[i] = L'%';
    }
    screen[nScreenWidth * nScreenHeight - 1] = '\0'; // null terminator


    // Create console handler (custom screen buffer)
    HANDLE hConsole{ CreateConsoleScreenBuffer(
        GENERIC_READ | GENERIC_WRITE, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL) };
    // Set Active Screen Buffer so that console will show this buffer first
    SetConsoleActiveScreenBuffer(hConsole);
    DWORD dwBytesWritten{ 0 };


    // Create world map
    std::wstring map{};

    map += L"################";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"#..............#";
    map += L"################";

    while (true) {
        // Write cavas into console to show screen 
        WriteConsoleOutputCharacter(hConsole, screen, nScreenWidth * nScreenHeight, { 0,0 }, &dwBytesWritten);
    }
    return 0;

}

接下來的十天,將會從這些基礎出發,正式踏進演算法的世界。
讓我們繼續走下去~


上一篇
Day 9 | Ray Casting : 玩家畫面 screen 以及 視野範圍 AoV 的關係
下一篇
Day 11 | Ray Casting : 從第一道光開始解析
系列文
用 C++ 實作簡易第一人稱視角遊戲:從入門到理解 Ray Casting30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言